using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication4
{
    public partial class Map : Form
    {
        public int spaceBetweenVillages = 1;
        World world;


        public event VillageSelectedDelegate VillageSelectedEvent;
        public delegate void VillageSelectedDelegate(Village vill);
        SolidBrush abondonedVillageBrush = new SolidBrush(Color.DarkGray);
        SolidBrush nonhighlightedVillageBrush;

        List<SolidBrush> brushesCache;

        Bitmap bmp = null;

        ICampaigns campaigns;

        public Map(World world, ICampaigns campaigns)
        {
            this.world = world;
            InitializeComponent();

            this.Name = world.Name;

            App.AppUpdatedEvent += new AppUpdatedDelegate(AppUpdated);
            this.campaigns = campaigns;
        }

        //VirtualZoom frmVirtualZoom;

        //Button btn;
        //void Map_MouseWheel(object sender, MouseEventArgs e)
        //{
           

        //    virtualZoom.Visible = true;
        //    if (e.Delta > 0)
        //    {
        //        if (virtualZoom.Value < 10)
        //        {
        //            virtualZoom.Value += 1;
        //        }
        //    }
        //    else
        //    {
        //        if (virtualZoom.Value > 1)
        //        {
        //            virtualZoom.Value -= 1;
        //        }
        //    }

        //    if (virtualZoom.Value > 0)
        //    {
        //        virtualZoom.Visible = true;
        //    }
        //    else
        //    {
        //        virtualZoom.Visible = false;
        //    }

            
        //}

        public Point offset
        {
            get
            {
                Point o = new Point();
                o.X = App.MapCenter.X - WorldWidth / 2;
                o.Y = App.MapCenter.Y - WorldHeight / 2;
                return o;
            }
        }


        private void AppUpdated()
        {
            //this.MapCenter = App.MapCenter;
        }


        public int WorldWidth
        {
            get
            {
                return ClientRectangle.Width / (App.mapZoom+spaceBetweenVillages);
            }
        }
        public int WorldHeight
        {
            get
            {
                return ClientRectangle.Height / (App.mapZoom+spaceBetweenVillages);
            }
        }
   


        private void Map_Load(object sender, EventArgs e)
        {
        }



        Rectangle virtualZoomRec;
        private void Map_Paint(object sender, PaintEventArgs e)
        {
            if (bmp == null)
            {
                bmp = CreateMap();
            }
            Graphics g = e.Graphics;
            g = Graphics.FromImage(bmp);
            
            //if (virtualZoom.Value > 1)
            //{
            //    virtualZoomRec = new Rectangle((ClientRectangle.Width - (ClientRectangle.Width / virtualZoom.Value)) / 2
            //        , (ClientRectangle.Height - (ClientRectangle.Height/ virtualZoom.Value)) /2
            //        , ClientRectangle.Width / virtualZoom.Value
            //        , ClientRectangle.Height / virtualZoom.Value);
            //    e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            //    e.Graphics.DrawImage(bmp, ClientRectangle, virtualZoomRec, GraphicsUnit.Pixel);
            //}
            //else
            //{
                e.Graphics.DrawImage(bmp, 0, 0, ClientRectangle, GraphicsUnit.Pixel);
            //}
            g.Dispose();
        }



        
        DataView viewMapHighlightsSorted;

        private Bitmap CreateMap()
        {                                  
            Bitmap bmp;
            Graphics g;

            DateTime timeStartOfDraw= DateTime.Now;
            DateTime timeCheckPoint1= DateTime.MinValue;
            TimeSpan dif;

            System.Diagnostics.Trace.Write("Drawing (" + DateTime.Now.ToLocalTime() + ").....");


            this.Parent.Cursor = Cursors.WaitCursor;
            //
            // Need to update village spacing
            //
            if (App.mapZoom > 2)
            {
                spaceBetweenVillages = 1;
            }
            else
            {
                spaceBetweenVillages = 0;
            }

            // Create a bitmap the size of the form.
            bmp = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);


            // Create a Graphics object that is not on the form.
            g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.FromArgb(50,100,30)), 0, 0,
              bmp.Width, bmp.Height);


            if (world != null)
            {
                int zoomWidth = this.WorldWidth;
                int zoomHeight = this.WorldHeight;

                // make sure rows with tribe index 0 are first so that we first highlight players
                viewMapHighlightsSorted = new DataView(App.dtMapHighlights, "", "TribeID", DataViewRowState.CurrentRows);

                DrawContinentAndSectorLines(g);
                CreateBrushes();
                nonhighlightedVillageBrush = new SolidBrush(App.nonSelectedColor);

                string select = "(X >= " + offset.X + " and X < " + (offset.X + zoomWidth  ) + ")"
                    + "AND (Y >= " + offset.Y + " and Y < " + (offset.Y + zoomHeight ) + ")";
                //if (!App.drawAbondonedVillage)
                //{
                //    select += " AND " + World.CONSTS.VillagesTable.Columns.TribeName + " <> 0";
                //}
                //if (!App.drawNonSelected && viewMapHighlightsSorted.Count  > 0)
                //{

                //    select += " AND (";
                //    for (int i = 0; i < viewMapHighlightsSorted.Count; i++)
                //    {
                //        if (i >= 1)
                //        {
                //            select += " OR ";
                //        }
                //        if (viewMapHighlightsSorted[i][App.CONSTS.MapHighlights.Columns.TribeIDIndex] != DBNull.Value)
                //        {
                //            select += World.CONSTS.VillagesTable.Columns.TribeName + " = " + viewMapHighlightsSorted[i][App.CONSTS.MapHighlights.Columns.TribeIDIndex].ToString();
                //        }
                //    }
                //    select += ")";
                //}

                DataRow[] drs = world.dtVillages.Select(select);


                timeCheckPoint1 = DateTime.Now;
                dif = new TimeSpan(DateTime.Now.Ticks - timeStartOfDraw.Ticks);
                System.Diagnostics.Trace.Write("To Check Point #1:" + dif.TotalSeconds.ToString() + "sec....");


                SolidBrush brush;

                
                int vilX, vilY, mapX, mapY;
                foreach (DataRow dr in drs)
                {
                    vilX = Convert.ToInt32(dr[World.CONSTS.VillagesTable.Columns.XIndex]);
                    vilY = Convert.ToInt32(dr[World.CONSTS.VillagesTable.Columns.YIndex]);
                    mapX = (vilX - offset.X) * (App.mapZoom+spaceBetweenVillages);
                    mapY = (vilY - offset.Y) * (App.mapZoom + spaceBetweenVillages);

                    if (GetVillageColor(dr, out brush))
                    {
                        g.FillRectangle(brush, mapX, mapY, App.mapZoom, App.mapZoom);
                    }
                }


            }

            this.Parent.Cursor = Cursors.Default;

            dif = new TimeSpan(DateTime.Now.Ticks - timeCheckPoint1.Ticks);
            System.Diagnostics.Trace.Write("To End:" + dif.TotalSeconds.ToString() + " sec....");
            dif = new TimeSpan(DateTime.Now.Ticks - timeStartOfDraw.Ticks);
            System.Diagnostics.Trace.WriteLine("Total:" + dif.TotalSeconds.ToString() + " sec....");

            if (WindowsApplication4.Properties.Settings.Default.ShowLegend)
            {
                DrawLegend(g);
            }



            return bmp;            
        }

        private void DrawLegend(Graphics g)
        {
            Point drawLoc = new Point(1, 1);
            Font font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
            foreach (DataRowView drv in viewMapHighlightsSorted)
            {
                Color color = Color.White;
                if (drv[App.CONSTS.MapHighlights.Columns.ColorIndex] != null && drv[App.CONSTS.MapHighlights.Columns.ColorIndex] != DBNull.Value)
                {
                    color = Color.FromArgb(Convert.ToInt32(drv[App.CONSTS.MapHighlights.Columns.ColorIndex]));
                }
                
                string playerName = drv[App.CONSTS.MapHighlights.Columns.PlayerNameIndex].ToString().Trim();

                if (!string.IsNullOrEmpty(playerName))
                {
                    Player player = Worlds.currentWorld.GetPlayer(playerName);
                    if (player != null)
                    {
                        TextRenderer.DrawText(g, playerName + " (" + player.Tribe.Tag + ")", font, drawLoc, color);
                        drawLoc.Y += 12;
                    }
                }
                else if (drv[App.CONSTS.MapHighlights.Columns.TribeIDIndex] != DBNull.Value)
                {
                    Tribe tribe = Worlds.currentWorld.GetTribe((int)drv[App.CONSTS.MapHighlights.Columns.TribeIDIndex]);
                    if (tribe != null)
                    {
                        TextRenderer.DrawText(g, tribe.Tag, font, drawLoc, color);
                        drawLoc.Y += 12;
                    }   
                }

            }
        }


        private void DrawContinentAndSectorLines(Graphics g)
        {
            //
            // vertical sector lines
            //
            int rem;
            int startX;
            Math.DivRem(offset.X, 5, out rem);
            if (rem == 0)
            {
                startX = offset.X;
            }
            else
            {
                startX = offset.X + 5-rem;
            }

            int mapX;
            for (int i = startX; i < offset.X + WorldWidth; i += 5)
            {
                mapX = (i - offset.X) * (App.mapZoom + spaceBetweenVillages) -1;

                g.DrawLine(new Pen(new SolidBrush(Color.FromArgb(33,75,34)), 1)
                    , new Point(mapX, 0)
                    , new Point(mapX, ClientRectangle.Height));
            }

            //
            // horizontal sector lines
            //
            
            int startY;
            Math.DivRem(offset.Y, 5, out rem);
            if (rem == 0)
            {
                startY = offset.Y;
            }
            else
            {
                startY = offset.Y + 5 - rem;
            }

            int mapY;
            for (int i = startY; i < offset.Y + WorldHeight; i += 5)
            {
                mapY = (i - offset.Y) * (App.mapZoom + spaceBetweenVillages) - 1;

                g.DrawLine(new Pen(new SolidBrush(Color.FromArgb(33, 75, 34)), 1)
                    , new Point(0, mapY)
                    , new Point(ClientRectangle.Width, mapY));
            }

            //
            // vertical continent lines
            //
            Math.DivRem(offset.X, 100, out rem);
            if (rem == 0)
            {
                startX = offset.X;
            }
            else
            {
                startX = offset.X + 100 - rem;
            }

                        for (int i = startX; i < offset.X + WorldHeight; i += 100)
            {
                mapX = (i - offset.X) * (App.mapZoom + spaceBetweenVillages) - 1;

                g.DrawLine(new Pen(new SolidBrush(Color.Black), 1)
                    , new Point(mapX, 0)
                    , new Point(mapX, ClientRectangle.Height));
            }


            //
            // horizontal continent lines
            //
            Math.DivRem(offset.Y, 100, out rem);
            if (rem == 0)
            {
                startY = offset.Y;
            }
            else
            {
                startY = offset.Y + 100 - rem;
            }

            for (int i = startY; i < offset.Y + WorldWidth; i += 100)
            {
                mapY = (i - offset.Y) * (App.mapZoom + spaceBetweenVillages) - 1;

                g.DrawLine(new Pen(new SolidBrush(Color.Black), 1)
                    , new Point(0, mapY)
                    , new Point(ClientRectangle.Width, mapY));
            }



        }

        
        private void CreateBrushes() 
        {
            brushesCache = new List<SolidBrush>(viewMapHighlightsSorted.Count);

            DataRowView drHighlights;
            for (int i = 0; i < viewMapHighlightsSorted.Count; i++)
            {
                drHighlights = viewMapHighlightsSorted[i];
                
                if (drHighlights[App.CONSTS.MapHighlights.Columns.ColorIndex] != null && drHighlights[App.CONSTS.MapHighlights.Columns.ColorIndex] != DBNull.Value)
                {
                    brushesCache.Add(new SolidBrush(Color.FromArgb(Convert.ToInt32(drHighlights[App.CONSTS.MapHighlights.Columns.ColorIndex]))));
                }
                else
                {
                    brushesCache.Add(new SolidBrush(Color.White));
                }
            }
        }

        private bool GetVillageColor(DataRow dr, out SolidBrush brush)
        {
            brush = nonhighlightedVillageBrush;

            if ((int)dr[World.CONSTS.VillagesTable.Columns.TribeIndex] == 0)
            {
                if (App.drawAbondonedVillage ) {
                    brush = abondonedVillageBrush;
                    return true;
                } else {
                    return false;
                }
            }

            bool highlightFound = false;
            DataRow drPlayer = dr.GetParentRow(Worlds.currentWorld.dtVillages.ParentRelations[0]);
            DataRowView drHighlights;
            for(int i = 0; i < viewMapHighlightsSorted.Count; i++)
            {
                drHighlights = viewMapHighlightsSorted[i];
                
                if (drPlayer[World.CONSTS.PlayersTable.Columns.NameIndex].ToString().Trim().ToUpper()
                        == drHighlights[App.CONSTS.MapHighlights.Columns.PlayerNameIndex].ToString().Trim().ToUpper())
                {
                    highlightFound = true;
                }
                else if (drHighlights[App.CONSTS.MapHighlights.Columns.TribeIDIndex] != DBNull.Value)
                {

                    if ((int)drPlayer[World.CONSTS.PlayersTable.Columns.AllyIndex]
                        == (int)drHighlights[App.CONSTS.MapHighlights.Columns.TribeIDIndex])
                    {
                        highlightFound = true;
                    }
                }

                if (highlightFound)
                {
                    brush = brushesCache[i];
                    return true;
                }
            }

            if (App.drawNonSelected)
            {
                //color = App.nonSelectedColor;
                brush = nonhighlightedVillageBrush;
                return true;
            }

            return false;
        }
       

        public void RedrawMap()
        {
            bmp = null;
            this.Invalidate();
        }

        private void Map_SizeChanged(object sender, EventArgs e)
        {
        }

        private void Map_ResizeEnd(object sender, EventArgs e)
        {
            if (resized)
            {
                RedrawMap();
                resized = false;
            }
        }

        private void Map_MouseClick(object sender, MouseEventArgs e)
        {
            Village village = FindVillage(e.X, e.Y);
            //frmMap.VillageSelected(village);
            VillageSelectedEvent(village);
        }

        private void Map_MouseHover(object sender, EventArgs e)
        {
//            Village village = FindVillage(lastMouseLocation.X, lastMouseLocation.Y);
  //          frmInfo.VillageSelected(village);
        }


        Point currentMouseLocation;

        private void Map_MouseMove(object sender, MouseEventArgs e)
        {
            System.Diagnostics.Trace.WriteLine("Mouse move " + DateTime.Now.Ticks.ToString());
            if (currentMouseLocation != e.Location)
            {
                currentMouseLocation = e.Location;
                Village village = FindVillage(e.X, e.Y);
                VillageSelectedEvent(village);
            }
        }

        private Village FindVillage(int x, int y)
        {
            Point worldCord;
                worldCord = GetWorldCordFromMapCord(x, y);


            return world.Village(worldCord.X, worldCord.Y);
            
        }

        bool resized = false;
        private void Map_Resize(object sender, EventArgs e)
        {
            resized = true;
            
        }

        //private Point GetWorldCordFromZoomCord(int x, int y)
        //{
        //    int mapX, mapY;

        //    mapX = (x / (App.mapZoom * virtualZoom.Value + spaceBetweenVillages * virtualZoom.Value)) + virtualZoomRec.X;
        //    mapY = (y / (App.mapZoom * virtualZoom.Value + spaceBetweenVillages * virtualZoom.Value)) + virtualZoomRec.Y;

        //    return GetWorldCordFromMapCord(mapX, mapY);
        //}

        private Point GetWorldCordFromMapCord(int x, int y)
        {
            int worldX, worldY;

            worldX = (x / (App.mapZoom + spaceBetweenVillages)) + offset.X;
            worldY = (y / (App.mapZoom + spaceBetweenVillages)) + offset.Y;

            return new Point(worldX, worldY);

        }
        private Point GetWorldCordFromMapCord(Point mapCord)
        {
            return GetWorldCordFromMapCord(mapCord.X, mapCord.Y);
        }


        public void SaveMapToFile()
        {
            saveFileDialog1.Filter = "Bitmap|*.bmp";
            if (WindowsApplication4.Properties.Settings.Default.Servertype == 0)
            {
                string worldfolder = "World" + WindowsApplication4.Properties.Settings.Default.world;

                saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\TW++ Saved Files\T" + worldfolder;
            }
            else if (WindowsApplication4.Properties.Settings.Default.Servertype == 1)
            {
                string worldfolder = "World" + WindowsApplication4.Properties.Settings.Default.world;

                saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\TW++ Saved Files\P" + worldfolder;
            }
            else if (WindowsApplication4.Properties.Settings.Default.Servertype == 2)
            {
                string worldfolder = "World" + WindowsApplication4.Properties.Settings.Default.world;

                saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\TW++ Saved Files\T_nl" + worldfolder;
            }
            
            if (saveFileDialog1.ShowDialog()  == DialogResult.OK)
            {
                bmp.Save(saveFileDialog1.FileName);
            }
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Point worldCord = GetWorldCordFromMapCord(currentMouseLocation);
            WindowsApplication4.Properties.Settings.Default.centerX = worldCord.X.ToString();
            WindowsApplication4.Properties.Settings.Default.centerY = worldCord.Y.ToString();
            App.MapCenter = worldCord;
           
            RedrawMap();
        }


        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            miHighlightPlayer.Visible = false;
            miHighlightTribe.Visible = false;
            miHighlightSeparator.Visible = false;
            miAddTargetAllVillages.Visible = false;
            miAddTargetVillage.Visible = false;
            miAddTargetVillages.Visible = false;
            miAddAttack.Visible = false;
            miCheckForLatestReportForAll.Visible = false;
            miCheckForLatestReport.Visible = false;

            Village vil = FindVillage(currentMouseLocation.X, currentMouseLocation.Y);
            if (vil != null)
            {

                Player player = vil.VillageOwner;
                //
                // Report retrieval 
                //
                miCheckForLatestReport.Text = "Check for latest report on " + App.FormatVillageForDisplay_Short(vil);
                //if (vil.VillageIntelligence != null)
                //{
                //    miCheckForLatestReport.Text += " (last checked " + DateTime.Now.Subtract(vil.VillageIntelligence.LastCheckeOn).TotalDa + " days ago)";
                //}
                miCheckForLatestReport.Tag = vil;
                miCheckForLatestReport.Visible = true;

                if (player != null)
                {
                    miCheckForLatestReportForAll.Text = "Check for latest reports for all villages of '" + player.Name + "'";
                    miCheckForLatestReportForAll.Tag = player;
                    miCheckForLatestReportForAll.Visible = true;
                }
                //
                // Highlighting
                //

                if (player != null)
                {
                    miHighlightSeparator.Visible = true;

                    miHighlightPlayer.Text = "Highlight Player '" + player.Name + "'";
                    miHighlightPlayer.Visible = true;
                    miHighlightPlayer.Tag = player.Name;

                    Tribe tribe = player.Tribe;

                    if (tribe != null)
                    {
                        miHighlightTribe.Text = "Highlight Tribe '"
                            + tribe.Tag
                            + " (" + tribe.Name + ")'";
                        miHighlightTribe.Visible = true;
                        miHighlightTribe.Tag = tribe.ID;
                    }
                }
                //
                // campaing controls
                //
                Compaign campaing = campaigns.CurrentCampaign;
                Target target = campaigns.CurrentTarget;

                if (campaing == null)
                {
                    miAddTargetVillage.Text = "Add " + App.FormatVillageForDisplay_Short(vil) + " as Target";
                    miAddTargetVillage.Tag = vil;
                    miAddTargetVillage.Visible = true;

                    #region TODO finish later
                    /*
                     * TODO finish later
                    if (player != null)
                    {
                        miAddTargetAllVillages.Text = "Add all villages of " + player.Name +" as Targets";
                        miAddTargetAllVillages.Visible = true;
                        miAddTargetVillages.Text = "Add all villages of " + player.Name + " near this village as Targets";
                        miAddTargetVillages.Visible = true;
                    }
                     * */
                    #endregion
                }
                else
                {
                    miAddTargetVillage.Text = "Add " + App.FormatVillageForDisplay_Short(vil) + " as Target to campaign '" + campaing.Name + "'";
                    miAddTargetVillage.Tag = vil;
                    miAddTargetVillage.Visible = true;
                }

                if (target != null)
                {
                    miAddAttack.Text = "Add " + App.FormatVillageForDisplay_Short(vil) + " as attack on " + App.FormatVillageForDisplay_Short(target.TargetVillage);
                    miAddAttack.Tag = vil;
                    miAddAttack.Visible = true;
                }


            }
            
        }

        private void miHighlightPlayer_Click(object sender, EventArgs e)
        {
            if (this.colorDialog.ShowDialog() != DialogResult.Cancel)
            {
                App.dtMapHighlights.Rows.Add(new object[]{DBNull.Value, (string)miHighlightPlayer.Tag, this.colorDialog.Color.ToArgb()}) ;
            }

            RedrawMap();

        }

        private void miHighlightTribe_Click(object sender, EventArgs e)
        {
            if (this.colorDialog.ShowDialog() != DialogResult.Cancel)
            {
                App.dtMapHighlights.Rows.Add(new object[] { (int)miHighlightTribe.Tag, String.Empty, this.colorDialog.Color.ToArgb() });
            }

            RedrawMap();

        }

        //private void virtualZoom_MouseMove(object sender, MouseEventArgs e)
        //{
        //    virtualZoom.Visible = true;
        //}

        //private void virtualZoom_ValueChanged(object sender, EventArgs e)
        //{
        //    if (virtualZoom.Value > 10)
        //    {
        //        virtualZoom.Value = 10;
        //    } else if (virtualZoom.Value < 0 ) {
        //        virtualZoom.Value = 1;

        //    }
        //    if (virtualZoom.Value > 1)
        //    {
        //        virtualZoom.Visible = true;
        //        this.Text = "Map - Virtual Zoom " + virtualZoom.Value.ToString() + "X";
        //    }
        //    else
        //    {
        //        virtualZoom.Visible = false;
        //        this.Text = "Map";
        //    }

        //    this.Invalidate();
        //}

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            Point worldCord = GetWorldCordFromMapCord(currentMouseLocation);
            WindowsApplication4.Properties.Settings.Default.centerX = worldCord.X.ToString();
            WindowsApplication4.Properties.Settings.Default.centerY = worldCord.Y.ToString();
            App.MapCenter = worldCord;

            RedrawMap();

        }

        private void addAllVilagesNearThisOneOfThisPlayerToCampaignToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void miAddTargetVillage_Click(object sender, EventArgs e)
        {
            campaigns.AddTarget((Village)miAddTargetVillage.Tag);
        }

        private void miAddAttack_Click(object sender, EventArgs e)
        {
            campaigns.AddAttack((Village)miAddAttack.Tag);
        }

        private void Map_Activated(object sender, EventArgs e)
        {

        }

        private void checkForLatestInteligenceOnThisVillageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            Village vil = (Village)miCheckForLatestReport.Tag;
            vil.CheckForLatestIntel();
            this.Cursor = Cursors.Default;
        }

        private void miCheckForLatestReportForAll_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            Player player = (Player)miCheckForLatestReportForAll.Tag;
            player.CheckForLatestIntel();
            this.Cursor = Cursors.Default;
        }

    }
}